<?php
/**
 * Created by PhpStorm.
 * User: dreamy
 * Date: 2021-12-13
 * Time: 15:16
 */
namespace common\services;

use common\models\StockProduct;
use common\models\StockRecord;
use common\models\StockWarehouse;
use common\models\TallyAccount;
use common\models\TallyCategory;
use common\models\TallyMember;
use common\models\TallyRecord;
use common\models\TallyStore;
use Yii;
use yii\helpers\ArrayHelper;
use yii\helpers\Json;
use yii\data\Pagination;

/**
 * Class TallyStockRecordService
 * @package common\services
 * 库存（进销存）销售采购记录
 */
class TallyStockRecordService extends BaseService
{

    /**
     * 获取符合条件的所有记录 不带分页的
     * @param array $condition
     *
     * @return array
     */
    public static function getExportAll($condition=[])
    {
        $query = self::getQuery(null,$condition);

        // 默认按创建时间倒叙
        $orderByStr = 'id desc';
        // 如果有筛选账单时间就按账单时间排序
        if(isset($condition['begin_date']) || isset($condition['end_date'])) {
            $orderByStr = 'tally_date desc,id desc';
        }

        $list  = $query
            ->orderBy($orderByStr)
            ->limit(10000)
            ->asArray()
            ->all();
        return $list ?: [];
    }

    /**
     * 返回符合查询条件的query
     * 增加逻辑 账户的筛选 转入 与 转出账户 都要包含
     * @param       $tallyId
     * @param array $condition
     *
     * @return \yii\db\ActiveQuery
     * @desc
     */
    public static function getQuery($tallyId,$condition=[])
    {
        $where = [
            'tally_id' => $tallyId
        ];
        // 从DB获取
        $query = StockRecord::find()
            ->select('*')
            ->where($where);
        // 上个id
        $last_id = ArrayHelper::getValue($condition,'last_id','');
        if($last_id){
            $query->andFilterWhere(['>','id',$last_id]);
        }
        // 分类ID
        $categoryId = ArrayHelper::getValue($condition,'category_id','');
        if($categoryId){
            $query->andFilterWhere(['=','category_id',$categoryId]);
        }
        // 分类ID集合
        $categoryIds = ArrayHelper::getValue($condition,'category_ids','');
        if($categoryIds){
            $query->andFilterWhere(['in','category_id',explode(',',$categoryIds)]);
        }
//        print_r($query->createCommand()->rawSql);
//        die;
        // 商家ID
        $storeId = ArrayHelper::getValue($condition,'store_id','');
        if($storeId){
            $query->andFilterWhere(['=','store_id',$storeId]);
        }
        // 商家ID集合
        $storeIds = ArrayHelper::getValue($condition,'store_ids','');
        if($storeIds){
            $query->andFilterWhere(['in','store_id',explode(',',$storeIds)]);
        }
        // 项目ID
        $projectId = ArrayHelper::getValue($condition,'project_id','');
        if($projectId){
            $query->andFilterWhere(['=','project_id',$projectId]);
        }
        // 项目ID集合
        $projectIds = ArrayHelper::getValue($condition,'project_ids','');
        if($projectIds){
            $query->andFilterWhere(['in','project_id',explode(',',$projectIds)]);
        }
        // 成员ID
        $memberId = ArrayHelper::getValue($condition,'member_id','');
        if($memberId){
            $query->andFilterWhere(['=','member_id',$memberId]);
        }
        // 成员ID集合
        $memberIds = ArrayHelper::getValue($condition,'member_ids','');
        if($memberIds){
            $query->andFilterWhere(['in','member_id',explode(',',$memberIds)]);
        }

        // 设置默认空 方便下面做判断
        if(!isset($condition['begin_date'])) $condition['begin_date'] = '';
        if(!isset($condition['end_date'])) $condition['end_date'] = '';

        // 时间段查询 包含右时间边界
        if($condition['begin_date'] != '' && $condition['end_date'] != '') {
            $condition['end_date'] = date('Y-m-d',strtotime('+1 day',strtotime($condition['end_date'])));
            $query->andFilterWhere(['between','tally_date',$condition['begin_date'], $condition['end_date']]);
        }
        if($condition['begin_date'] != '' && $condition['end_date'] == '') {
            $query->andFilterWhere(['>','tally_date',$condition['begin_date']]);
        }
        if($condition['begin_date'] == '' && $condition['end_date'] != '') {
            $condition['end_date'] = date('Y-m-d',strtotime('+1 day',strtotime($condition['end_date'])));
            $query->andFilterWhere(['<','tally_date',$condition['end_date']]);
        }

//        print_r($query->createCommand()->rawSql);
//        die;
        // 备注关键词
        $memo = ArrayHelper::getValue($condition,'memo','');
        if(!$memo) {
            $memo = ArrayHelper::getValue($condition,'keywords','');
        }
        if($memo){
            $query->andFilterWhere(['like','memo',$memo]);
        }
        // 包含状态
        $state = ArrayHelper::getValue($condition,'state');
        if($state !== null){
            $query->andFilterWhere(['=','state',$state]);
        }
        return $query;
    }

    /**
     * 获取某个账套下的记录列表
     * @param       $tallyId
     * @param array $condition
     *
     * @return array
     */
    public static function getList($tallyId,$condition=[])
    {
        $query = self::getQuery($tallyId,$condition);

        // 分页相关
        $count = $query->count();
        // 构造分页对象
        $pageSize = $_SERVER['PAGE_SIZE'] ?: 10 ;
        $pagination = new Pagination([
            'defaultPageSize' => $pageSize,
            'totalCount' => $count
        ]);
        $pagination->validatePage=false;

        // 从DB获取
        $recordList = $query->orderBy('id desc')
            ->offset($pagination->offset)
            ->limit($pagination->limit)
            ->asArray()
            ->all();

        // 返回带分页数据
        return [
            'data'       => $recordList ?: [],
            'pageInfo'   => [
                'totalCount' => intval($count) ,
                'pageSize'   => intval($pageSize)
            ]
        ];
    }

    /**
     * 获取单个记录信息
     * @param $recordId
     * @param $tallyId
     *
     * @return array
     */
    public static function getInfoById($recordId,$tallyId)
    {
        $where = [
            'id'    => $recordId,
            'tallyId' => $tallyId
        ];

        $info = StockRecord::find()
            ->select('*')
            ->where($where)
            ->asArray()
            ->limit(1)
            ->one();
        return $info ?: [];
    }

    /**
     * 添加一条库存账单记录（会触发记账逻辑）
     * @param $formData
     * @return bool
     */
    public static function create($formData)
    {
        $model = new StockRecord();
        $productDetail = ArrayHelper::getValue($formData,'product_detail');
        if(!empty($productDetail)) {
            $formData['product_detail'] = json_encode($productDetail,JSON_UNESCAPED_UNICODE);
        }

        // 补全账户信息
        if(isset($formData['account_id']) && $formData['account_id'] > 0 ) {
            $accountInfo = TallyAccount::find()->where([
                'id' => $formData['account_id'],
                'tally_id' => $formData['tally_id']
            ])->asArray()->one();
            if(!$accountInfo) {
                self::setError('账户不能为空');
                return false;
            }else {
                $formData['account_name'] = $accountInfo['title'];
            }
        }

        // 补全分类信息
        if(isset($formData['category_id']) && $formData['category_id'] > 0 ) {
            $cateTitle = TallyCategoryService::getTitleGlobal($formData['category_id']);
            if(!$cateTitle) {
                self::setError('分类信息不存在');
                return false;
            }else {
                $formData['category_name'] = $cateTitle;
            }
        }

        // 补全员工信息
        if(isset($formData['member_id']) && $formData['member_id'] > 0) {
            $memberInfo = TallyMember::find()->where([
                'id' => $formData['member_id'],
                'tally_id' => $formData['tally_id']
            ])->asArray()->one();
            if(!$memberInfo) {
                self::setError('员工信息不存在');
                return false;
            }else {
                $formData['member_name'] = $memberInfo['name'];
            }
        }

        // 补全供应商信息
        if(isset($formData['store_id']) && $formData['store_id'] > 0 ) {
            $storeInfo = TallyStore::find()->where([
                'id' => $formData['store_id'],
                'tally_id' => $formData['tally_id']
            ])->asArray()->one();
            if(!$storeInfo) {
                self::setError('供应商信息不存在');
                return false;
            }else {
                $formData['store_name'] = $storeInfo['title'];
            }
        }

        $model->load($formData,'');
        if ($model->validate() && $model->save()) {
            // TODO.... 触发账单记录的增加（ 标记账单类型 + 回传recordId）
            // 返回处理后的完成状态 recordId、state:1已入账 0待审核

            return $model->id ;
        }else{
            Yii::error('StockRecord insert error:'.current($model->getFirstErrors()).';post:'.Json::encode($formData,JSON_UNESCAPED_UNICODE));
            self::setError(current($model->getFirstErrors()));
            return false;
        }
    }

    /**
     * 账单删除（库存记录删除 + 同步账单删除）
     * @param $condition
     * @return bool
     * @throws
     */
    public static function delete($condition)
    {
        $model = StockRecord::find()->where($condition)->one();
        if(!$model){
            self::setError('记录不存在');
            return false ;
        }
        // 对应账单的触发删除、删除后账户要进行逆转
        TallyRecordService::delete([
            'uid' => ArrayHelper::getValue($condition,'uid'),
            'id' => $model->record_id,
            'tally_id' => $model->tally_id,
        ]);
        if ($model->delete()) {
            return true;
        }else{
            self::setError(current($model->getFirstErrors()));
            return false;
        }
    }

    /**
     * 更新记录状态
     * @param $condition
     * @param $newState
     *
     * @return bool
     */
    public static function updateSate($condition,$newState)
    {
        $model = StockRecord::find()->where($condition)->one();
        $model->state = $newState;
        $saveRes = $model->save();
        if($saveRes) {
            return true;
        }else {
            self::setError(current($model->getFirstErrors()));
            return false;
        }
    }

    /**
     * 处理产品流动
     * @param     $stockId
     * @param int $recordId
     * @param bool $reverse
     *
     * @return bool
     */
    public static function handleProductFlow($stockId,$recordId=0,$reverse=false)
    {
        $model = StockRecord::find()->where([
            'id' => $stockId
        ])->one();
        // handle 处理产品的库存流动
        self::processProductFlow(ArrayHelper::toArray($model),$reverse);
        // 标记状态
        if($recordId) {
            $model->record_id = $recordId;
        }

        $newState = StockRecord::STATE_VALID;

        // 存在反转 说明删除单
        if($reverse) {
            $newState = StockRecord::STATE_DELETED;
        }

        $model->state = $newState;
        $model->save();
        return true;
    }

    /**
     * 处理数据流动的核心办法
     * @param $stockRecordInfo
     * @param bool $reverse
     *
     * @return bool
     */
    public static function processProductFlow($stockRecordInfo,$reverse=false)
    {
        // 主要处理产品的变动、流入、流出、 只是区分是入库还是出库即可
        $productDetail = $stockRecordInfo['product_detail'];
        $productDetail = json_decode($productDetail,true);
        $saleType = $stockRecordInfo['sales_type'];
        if($saleType == StockRecord::OPT_TYPE_SALE || $saleType == StockRecord::OPT_TYPE_PURCHASE_REFUND) {
            // 库存减少的
            $optType = 'out';
        }else {
            // 库存增加的
            $optType = 'in';
        }

        // 存在逆向反转
        if($reverse) {
            if($optType == 'in') $optType = 'out';
            if($optType == 'out') $optType = 'in';
        }

        $tallyId = $stockRecordInfo['tally_id'];

        // 仓库信息
        $houseId = $stockRecordInfo['house_id'];
        $houseInfo = StockWarehouse::find()->where([
            'id' => $houseId,
            'tally_id' => $tallyId,
        ])->asArray()->one();

        // 记账日期
        $tallyDate = ArrayHelper::getValue($stockRecordInfo,'tally_date');
        // 一次性拉取全部产品基础信息
        $productIds = ArrayHelper::getColumn($productDetail,'product_id');

        $groupData = StockProduct::find()->where([
            'tally_id' => $tallyId,
        ])->andFilterWhere([
            'in', 'id', $productIds
        ])->asArray()->all();
        if(count($groupData) != count($productIds)) {
            self::setError('部分产品数据不存在 请检查');
            return false;
        }
        $productTempData = [];
        foreach ($groupData as $gv) {
            $productId = $gv['id'];
            $productTempData[$productId] = $gv;
        }

        // 遍历产品 执行处理添加逻辑 遍历插入库存明细
        foreach ($productDetail as $pv) {
            // 产品名称 + 产品ID + 入口数量 + 成本价折算 + 入库时间
            $productId = $pv['product_id'];
            // 产品信息
            $productInfo =  $productTempData[$productId];

            $inNum = 0;
            $outNum = 0;
            if($optType == 'in') {
                $inNum = $pv['num'];
                $outNum = 0;
            }else if($optType == 'out') {
                $inNum = 0;
                $outNum = $pv['num'];
            }

            // 库存流水取成本价
            $balanceMoney = ToolService::moneyFormat($pv['num']*$productInfo['cost_price']);

            // 准备入库数据
            $balanceDetailFormData = [
                'tally_id' => $tallyId,
                'product_id' => $productId,
                'product_title' => $productInfo['title'],
                'product_spec' => $productInfo['spec'],
                'product_unit' => $productInfo['unit'],
                'product_cost_price' => $balanceMoney,
                'house_id' => $houseId,
                'house_title' => $houseInfo['title'],
                'in_num' => $inNum,
                'out_num' => $outNum,
                'balance_money' => $balanceMoney,
                'tally_date' => $tallyDate,
                'stock_record_id'=>$stockRecordInfo['id']
            ];

            TallyStockBalanceService::addDetail($balanceDetailFormData);
        }

        // 触发总表 产品 仓库 二维统计数据的更新
        foreach ($productDetail as $pv) {
            $productId = $pv['product_id'];
            $productInfo =  $productTempData[$productId];
            TallyStockBalanceService::syncProductBalance($tallyId,$productId,$productInfo);
            // 触发总表 仓库维度数据更新
            TallyStockBalanceService::syncProductHouseBalance($tallyId,$houseId,$houseInfo,$productId,$productInfo);
        }

        return true;

    }

}
